package com.particles.particles.objects;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.Log;

import com.particles.particles.data.IndexBuffer;
import com.particles.particles.data.VertexBuffer;
import com.particles.particles.programs.HeightmapShaderProgram;

import static android.opengl.GLES20.GL_ELEMENT_ARRAY_BUFFER;
import static android.opengl.GLES20.GL_TRIANGLES;
import static android.opengl.GLES20.GL_UNSIGNED_SHORT;
import static android.opengl.GLES20.glBindBuffer;
import static android.opengl.GLES20.glDrawElements;

/**
 * Created by Cuckoo322 on 4/19/2017.
 */

public class Heightmap {

    private static final int POSITION_COMPONENT_COUNT = 3;

    private final int width;
    private final int height;
    private final int numElements;
    private final VertexBuffer vertexBuffer;
    private final IndexBuffer indexBuffer;

    public Heightmap(Bitmap bitmap) {
        width = bitmap.getWidth();
        height = bitmap.getHeight();

        //地形图大小最大为256 * 256
        // 因为使用short类型，65536是short最大支持32767的2倍，由于作为无符号值读入，所以能支持65536
        Log.d("Heightmap", "width: "+width+"; height: "+height+"; width * height = "+width * height);
        if (width * height > 65536) {
            throw new RuntimeException("地形图太大以致不能放进索引缓冲区");
        }
        numElements = calculateNumElement();
        vertexBuffer = new VertexBuffer(loadBitmapData(bitmap));
        indexBuffer = new IndexBuffer(createIndexData());
    }

    private float[] loadBitmapData(Bitmap bitmap) {
        final int[] pixels = new int[width * height];
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
        bitmap.recycle();

        final float[] heightmapVertices = new float[width * height * POSITION_COMPONENT_COUNT];
        int offset = 0;

        //把位图像素点的数据转换为高度图的数据
        for (int row = 0; row < height; row++) {
            for (int col = 0; col < width; col++) {
                final float xPosition = ((float) col / (float) (width - 1)) - 0.5f;
                //红色越大高度越高
                final float yPosition = (float) Color.red(pixels[row * height + col]) / 255.0f;
                final float zPosition = ((float) row / (float) (height - 1)) - 0.5f;

                heightmapVertices[offset++] = xPosition;
                heightmapVertices[offset++] = yPosition;
                heightmapVertices[offset++] = zPosition;
            }
        }

        return heightmapVertices;
    }

    /**
     * 计算需要多少个索引元素
     * 每4个顶点组成1个面，需要2个三角形，每个三角形包含3个顶点
     * @return
     */
    private int calculateNumElement() {
        return (width - 1) * (height - 1) * 2 * 3;
    }

    /**
     * 想象成地形图是一堆网格，每4四个相近的顶点组成一个格子
     * @return
     */
    private short[] createIndexData() {
        final short[] indexData = new short[numElements];
        int offset = 0;

        for (int row = 0; row < height - 1; row++) {
            for (int col = 0; col < width - 1; col++) {
                short topLeftIndexNum = (short) (row * width + col);
                short topRightIndexNum = (short) (row * width + col + 1);
                short bottomLeftIndexNum = (short) ((row + 1) * width + col);
                short bottomRightIndexNum = (short) ((row + 1) * width + col + 1);

                //利用2个三角形组成1个矩形
                indexData[offset++] = topLeftIndexNum;
                indexData[offset++] = bottomLeftIndexNum;
                indexData[offset++] = topRightIndexNum;

                indexData[offset++] = topRightIndexNum;
                indexData[offset++] = bottomLeftIndexNum;
                indexData[offset++] = bottomRightIndexNum;
            }
        }

        return indexData;
    }

    public void bindData(HeightmapShaderProgram heightmapShaderProgram) {
        vertexBuffer.setVertexAttribPointer(
                0,
                heightmapShaderProgram.getaPositionAttributeLocation(),
                POSITION_COMPONENT_COUNT,
                0
        );
    }

    public void draw() {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.getBufferId());
        glDrawElements(GL_TRIANGLES, numElements, GL_UNSIGNED_SHORT, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    }
}
